package com.lam.system.controller;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.lam.common.base.domain.LoginUser;
import com.lam.common.base.domain.Result;
import com.lam.common.base.domain.tree.TreeUtil;
import com.lam.common.components.captcha.service.CaptchaService;
import com.lam.common.components.file.FileDownloadUtil;
import com.lam.common.components.file.model.FileBusiTypeEnum;
import com.lam.common.config.CommonConfig;
import com.lam.common.constant.CommonConstant;
import com.lam.common.context.AuthTypeEnum;
import com.lam.common.context.TokenUtils;
import com.lam.common.utils.CollectionUtil;
import com.lam.common.utils.JsonUtil;
import com.lam.common.utils.NumberUtil;
import com.lam.common.utils.PasswordUtil;
import com.lam.common.utils.StringUtils;
import com.lam.common.utils.file.FileUploadUtil;
import com.lam.common.validate.ValidateUtil;
import com.lam.framework.operLog.annotation.Log;
import com.lam.framework.operLog.enums.BusinessType;
import com.lam.framework.operLog.enums.LogSave;
import com.lam.system.domain.LoginBody;
import com.lam.system.domain.RouterVo;
import com.lam.system.entity.SysMenu;
import com.lam.system.entity.SysUser;
import com.lam.system.service.SysMenuService;
import com.lam.system.service.SysUserService;
import com.lam.system.util.MenuUtil;

/**
 * 后端登录验证
 */
@Log(title = "后端登录")
@RestController
@RequestMapping("/${adminPath}/index")
public class SysLoginController {
	
	private final Logger logger = LoggerFactory.getLogger(this.getClass());

	@Autowired
	private SysMenuService sysMenuService;
	@Autowired
	private SysUserService sysUserService;
	@Autowired
	private CaptchaService captchaService;
	@Resource
	private AuthenticationManager authenticationManager;

	/**
	 * 登录方法
	 * 
	 * @param loginBody 登录信息
	 * @return 结果
	 */
	@Log(businessType = BusinessType.LOGIN_IN)
	@PostMapping("/login")
	public Result login(@RequestBody LoginBody loginBody) {

		ValidateUtil.validRequired(loginBody.getUsername(), "用户名不能为空！");
		ValidateUtil.validRequired(loginBody.getLoginPwd(), "密码不能为空！");

		if (!captchaService.checkCode(loginBody.getUsername(), loginBody.getCategory(), loginBody.getCodeObject())) {
			logger.error("登录验证码错误! username:{}", loginBody.getUsername());
			return Result.fail("验证码错误！").data("refreshCode");
		}
		
		String username = loginBody.getUsername();
		//1. 校验用户是否有效
		SysUser sysUser = sysUserService.selectByUsername(username);
		//情况1：该用户不存在
		if (sysUser == null) {
			logger.error("登录时检查到该账户不存在， username:{}", username);
			return Result.fail("用户名或密码错误！").data("refreshCode");
		}
		//情况2：判断用户是否已禁用
		if (!NumberUtil.eq(CommonConstant.STATUS_NORMAL_1, sysUser.getStatus())) {
			logger.error("登录时检查到该账户已禁用， username:{}", username);
			return Result.fail("账号不可用！").data("refreshCode");
		}
		//情况3：判断用户是否有登录权限
		if (!TokenUtils.checkAllowAdm(sysUser.getUserType())) {
			logger.error("登录时检查到该账户没有后端登录权限， username:{}, userType：{}", username, sysUser.getUserType());
			return Result.fail("errorTip.accountNotAvailable").data("refreshCode");
		}
		
		//2. 校验用户密码是否正确
		String userpassword = PasswordUtil.encrypt(username, loginBody.getLoginPwd(), sysUser.getSalt());
		if (!StringUtils.equals(sysUser.getPassword(), userpassword)) {
			return Result.fail("用户名或密码错误！").data("refreshCode");
		}
		
    	LoginUser loginUser = JsonUtil.toJavaObject(sysUser, LoginUser.class, "id=>userId", "username", "regType", "nickName", "realname", 
    			"email", "phone", "avatar", "sex", "status", "post", "userType", "isNew", "remark");
    	
    	//加载用户的角色和权限
    	loginUser.setAuthType(AuthTypeEnum.ADMIN.getAuthType());
    	loginUser.setRegType(CommonConstant.REG_TYPE_PASSWD);
    	TokenUtils.setCleintInfo(loginUser);
    	Set<String> roles = sysUserService.loadUserRoles(loginUser.getUserId());
    	Set<String> permissions = sysUserService.loadUserAdmAuths(loginUser.getUserId());

    	loginUser.setRememberMe(loginBody.isRememberMe());
    	loginUser.setTokenExpires(loginBody.isRememberMe()?TokenUtils.TOKEN_EXPIRE_TIME_7_DAY:TokenUtils.TOKEN_EXPIRE_TIME_DEFAULT);
		// 获取用户
    	Map<String, Object> obj = new HashMap<>();
		// 生成token
		obj.put("token", TokenUtils.createToken(loginUser, roles, permissions));
		obj.put("username", loginUser.getUsername());
		obj.put("exp", loginUser.getTokenExpires());
		
		logger.info("用户登录成功! username:{}, userType：{}", username, sysUser.getUserType());
		return Result.ok("登录成功！").data(obj);
	}

	/**
	 * 查询用户拥有的菜单权限和按钮权限
	 *
	 * @return
	 */
	@Log(oper = "加载首页信息", logSave = LogSave.YES, saveResData = false)
	@GetMapping("/info")
	public Result indexInfo() {
		
		LoginUser loginUser = TokenUtils.getLoginUser();
		
		List<SysMenu> menuList = sysMenuService.selectMenuByUser(loginUser.getUserId());
		List<RouterVo> menuVoList = MenuUtil.buildMenus(TreeUtil.buildTree(menuList, MenuUtil.MENU_TOP_ID));
		
		Map<String, Object> userInfo = CollectionUtil.java2Map(loginUser, "username", "realname", "nickName", "sex", "email");
		userInfo.put("avatar", FileDownloadUtil.getDownloadInfo(FileBusiTypeEnum.AVATAR, loginUser.getAvatar()));
		
		Set<?> roles;
		Set<?> permissions;
		if(CommonConfig.me().isDev()||CommonConfig.me().isSit()) {
			roles = sysUserService.loadUserRoles(loginUser.getUserId());
	    	permissions = sysUserService.loadUserAdmAuths(loginUser.getUserId());
	    	TokenUtils.setLoginUserAuths(loginUser, roles, permissions);
		}else {
			roles = TokenUtils.getLoginUserRoles();
			permissions = TokenUtils.getLoginUserPermissions();
		}
		
		Map<String, Object> json = new HashMap<>();
		json.put("menus", menuVoList);
		json.put("roles", roles);
		json.put("auths", permissions);
		json.put("userInfo", userInfo);
		json.put("resourceUrl", FileUploadUtil.getResourceUrl());
		json.put("exp", TokenUtils.getLoginExpire(TokenUtils.getToken()));
		return Result.ok(json);
	}
	
}
